﻿using Mapster;
using WH.Contracts.Systems.KeyValues;
using WH.Model.Systems;
using WH.Repositories.IRepositories.ISystem;
using WH.Services.BaseService;
using WH.Services.IServices.ISystem;
using Rw.Core.Common;
using Rw.Core.Common.Paging;
using WH.Common.Constant;
using WH.Common.CustomException;
using SqlSugar;

namespace WH.Services.Services.System
{
    public class KeyValueService : BaseService<KeyValueEntity>, IKeyValueService
    {
        private IKeyValueRepository _keyValueRepository;

        public KeyValueService(IKeyValueRepository keyValueRepository) : base(keyValueRepository)
        {
            _keyValueRepository = keyValueRepository;
        }

        public async Task<int> CreateAsync(KeyValueInputDto input)
        {
            var exist = await _keyValueRepository.ExistsAsync(a => a.ParentId == input.ParentId && a.Name == input.Name && a.IsEnable);
            if (exist)
            {
                throw new BadRequestException($"请确保{input.Name}名称当前层级唯一，请重新操作");
            }

            exist = await _keyValueRepository.ExistsAsync(a => a.Code == input.Code && a.IsEnable);//&& a.ParentId == input.ParentId
            if (exist)
            {
                throw new BadRequestException($"请确保{input.Code}编号全局唯一，请重新操作");
            }

            var isTop = input.ParentId == BusinessFunction.TopParentId;

            var id = Snowflake.GetNewId();
            var layer = 0;
            var link = $"{id}";
            var isLeaf = true;
            if (!isTop)
            {
                var parent = await _keyValueRepository.FirstOrDefaultAsync(x => x.Id == input.ParentId || x.Code == input.ParentId);
                if (parent == null)
                {
                    throw new BadRequestException($"父级不存在，请重新操作");
                }

                layer = parent.Layer + 1;
                link = $"{parent.Link}|{link}";

                parent.IsLeaf = false;
                await _keyValueRepository.UpdateAsync(parent);

                input.ParentId = parent.Id;
            }
            var keyValue = new KeyValueEntity
            {
                Id = Snowflake.GetNewId(),
                Name = input.Name,
                Code = input.Code,
                SortCode = input.SortCode,
                IsEnable = input.IsEnable,
                ParentId = input.ParentId,
                Layer = layer,
                Link = link,
                IsLeaf = isLeaf,
                IsDeletable = true,
                IconUrl = input.IconUrl ?? "",
                InputCode = input.InputCode,
            };

            var res = await _keyValueRepository.CreateAsync(keyValue);

            return res;
        }


        public async Task<int> UpdateAsync(string id, KeyValueInputDto input)
        {
            var exist = await _keyValueRepository.ExistsAsync(a => a.Id != id && a.ParentId == input.ParentId && a.Name == input.Name && a.IsEnable);
            if (exist)
            {
                throw new BadRequestException($"请确保{input.Name}名称当前层级唯一，请重新操作");
            }

            exist = await _keyValueRepository.ExistsAsync(a => a.Id != id && a.Code == input.Code && a.IsEnable);//&& a.ParentId == input.ParentId
            if (exist)
            {
                throw new BadRequestException($"请确保{input.Code}编号全局唯一，请重新操作");
            }

            var keyValue = await _keyValueRepository.FirstOrDefaultAsync(a => a.Id == id);
            if (keyValue == null)
            {
                throw new BadRequestException($"未查找到该{input.Name}名称，请重新操作");
            }


            var isTop = input.ParentId == BusinessFunction.TopParentId;
            var layer = 0;
            var link = $"{id}";
            if (!isTop)
            {
                var parent = await _keyValueRepository.FirstOrDefaultAsync(x => x.Id == input.ParentId || x.Code == input.ParentId);
                if (parent == null)
                {
                    throw new BadRequestException("父级不存在，请重新操作");
                }

                layer = parent.Layer + 1;
                link = $"{parent.Link}|{link}";


                if (parent.Id != keyValue.ParentId && !string.IsNullOrWhiteSpace(keyValue.ParentId))
                {
                    var oldParent = await _keyValueRepository.FindByIdAsync(keyValue.ParentId);
                    if (oldParent != null)
                    {
                        var oldParentHasChildren = await _keyValueRepository.ExistsAsync(a => a.ParentId == parent.Id && a.Id != id);
                        oldParent.IsLeaf = !oldParentHasChildren;
                        await _keyValueRepository.UpdateAsync(oldParent);
                    }
                }

                parent.IsLeaf = false;
                await _keyValueRepository.UpdateAsync(parent);

                input.ParentId = parent.Id;
            }

            var hasChildren = await _keyValueRepository.ExistsAsync(a => a.ParentId == id);
            var isLeaf = !hasChildren;

            keyValue.ParentId = input.ParentId;
            keyValue.Code = input.Code;
            keyValue.Name = input.Name;
            keyValue.Link = link;
            keyValue.Layer = layer;
            keyValue.IsLeaf = isLeaf;
            keyValue.IconUrl = input.IconUrl ?? "";
            keyValue.InputCode = input.InputCode;
            keyValue.SortCode = input.SortCode;
            keyValue.IsEnable = input.IsEnable;

            var res = await _keyValueRepository.UpdateAsync(keyValue);

            return res;
        }

        public async Task<KeyValueOutputDto> GetKeyValByCodeAsync(string codeOrId)
        {
            var result = await _keyValueRepository.FirstOrDefaultAsync(k => k.Code == codeOrId || k.Id == codeOrId, true);

            return result.Adapt<KeyValueOutputDto>();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="code"></param>
        /// <returns></returns>
        public async Task<List<KeyValueOutputDto>> GetKeyValueChildByCodeListAsync(string code)
        {

            var keyvals = await _keyValueRepository.FindAllAsync(k => k.IsEnable, true);

            var result = keyvals.FirstOrDefault(k => (k.Code == code || k.Id == code) && k.IsEnable);

            var dataList = new List<KeyValueOutputDto>();

            if (result is not null)
            {
                var data = keyvals.Where(x => x.ParentId.Equals(result.Id) && x.IsEnable).ToList();

                dataList = data.Adapt<List<KeyValueOutputDto>>();
            }
            return dataList;
        }

        public async Task<KeyValueTreeOutputDto> FindTree(string code)
        {
            var begin = await _keyValueRepository.FirstOrDefaultAsync(k => k.Code == code || k.Id == code);

            if (begin is null)
            {
                return default;
            }

            var data = begin.Adapt<KeyValueTreeOutputDto>();
            data.Children = await GetTreeNode(data.Id, true);
            if (data.Children is null || !data.Children.Any())
            {
                data.IsLeaf = true;
            }
            return data;
        }

        public async Task<IList<KeyValueTreeOutputDto>> FindTreeByParentId(string parentId)
        {
            var list = await _keyValueRepository.FindAllAsync();

            var data = list.Adapt<IList<KeyValueTreeOutputDto>>().OrderByDescending(x => x.SortCode).ToList();//.Where(x => x.IsLeaf == false)

            var nodes = GetTreeNode(data, parentId);

            return nodes;
        }

        public async Task<IList<KeyValueTreeOutputDto>> FindTreeAllByParentCode(string code)
        {
            var first = await _keyValueRepository.FirstOrDefaultAsync(x => x.Code == code && x.IsEnable);

            var data = first.Adapt<KeyValueTreeOutputDto>();

            var nodes = await GetTreeNode(data.Id);

            var res = GetTreeALL(nodes ?? new List<KeyValueTreeOutputDto>());

            return res;
        }

        public async Task<IList<KeyValueTreeOutputDto>> FindTreeAllAndSelfByParentCode(string code)
        {
            var first = await _keyValueRepository.FirstOrDefaultAsync(x => x.Code == code && x.IsEnable);

            var data = first.Adapt<KeyValueTreeOutputDto>();

            var nodes = await GetTreeNode(data.Id);

            var res = GetTreeALL(nodes ?? new List<KeyValueTreeOutputDto>());

            var list = new List<KeyValueTreeOutputDto>() { data };

            list.AddRange(res);

            return list;
        }

        public async Task<IPagedList<KeyValueTreeOutputDto>> GetTreeValues(string parentId, Pager pager)
        {
            var list = await _keyValueRepository.PagedFindAllAsync(x => x.ParentId == parentId, x => x.SortCode, OrderByMode.Desc, pager);

            var nodes = list.Adapt<PagedList<KeyValueTreeOutputDto>>();

            return nodes;
        }


        private async Task<bool> CheckLastLeafLayer(string Id)
        {
            return (await _keyValueRepository.FindAllAsync(x => x.ParentId == Id && x.IsLeaf == true)).Any();
        }

        /// <summary>
        /// 生成菜单树
        /// </summary>
        /// <param name="list"></param>
        /// <param name="parentId"></param>
        /// <returns></returns>
        private IList<KeyValueTreeOutputDto> GetTreeNode(IList<KeyValueTreeOutputDto> list, string parentId)
        {
            var p = list.FirstOrDefault(x => x.Id == parentId || x.Code == parentId);

            if (p is null && parentId != BusinessFunction.TopParentId)
            {
                return new List<KeyValueTreeOutputDto>();
            }

            parentId = p?.Id ?? BusinessFunction.TopParentId;

            var nodes = list.Where(x => x.ParentId == parentId).ToList();

            foreach (var item in nodes)
            {
                item.Children = GetTreeNode(list, item.Id ?? "");
                if (!item.Children.Any())
                {
                    item.IsLeaf = true;
                }
            }

            return nodes;
        }

        private async Task<List<KeyValueTreeOutputDto>?> GetTreeNode(string parentId, bool onlyEnable = false)
        {
            var list = (await _keyValueRepository.FindAllAsync(null, true)).Where(k => k.ParentId == parentId);

            if (onlyEnable)
            {
                list = list.Where(x => x.IsEnable);
            }

            if (list is not null)
            {
                var nodes = list.Adapt<List<KeyValueTreeOutputDto>>();
                foreach (var item in nodes)
                {
                    item.Children = await GetTreeNode(item.Id);

                    if (item.Children is null || !item.Children.Any())
                    {
                        item.IsLeaf = true;
                    }
                }

                return nodes;
            }
            else
            {
                return default;
            }
        }


        private IList<KeyValueTreeOutputDto> GetTreeALL(IList<KeyValueTreeOutputDto> nodes)
        {
            var data = new List<KeyValueTreeOutputDto>();

            data.AddRange(nodes);
            foreach (var item in nodes)
            {
                if (item.Children is not null && item.Children.Any())
                {
                    data.AddRange(GetTreeALL(item.Children));
                }
            }

            return data;
        }



        public async Task<IEnumerable<KeyValueOutputDto>> GeKeyValuesAsync(KeyValueInputDto input)
        {
            var exp = Expressionable.Create<KeyValueEntity>(); //创建表达式

            if (!string.IsNullOrWhiteSpace(input.Code))
            {
                exp.And(x => x.Code == input.Code);
            }
            if (!string.IsNullOrWhiteSpace(input.ParentId))
            {
                exp.And(x => x.ParentId == input.ParentId);
            }
            if (!string.IsNullOrWhiteSpace(input.InputCode))
            {
                exp.And(x => x.InputCode == input.InputCode);
            }

            var keyValues = await _keyValueRepository.FindAllAsync(exp.ToExpression());

            return keyValues.Adapt<IEnumerable<KeyValueOutputDto>>();
        }

        public async Task<KeyValueOutputDto?> GetKeyValueByCodeAsync(string code)
        {
            var data = await _keyValueRepository.GetKeyValueByCodeAsync(code);

            return data?.Adapt<KeyValueOutputDto>();
        }

        public async Task<string[]> GetChildIds(string parentId)
        {
            return await _keyValueRepository.GetChildIds(parentId);
        }
    }
}
